package com.spzx.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.domain.Product;
import com.spzx.product.domain.ProductDetails;

import com.spzx.product.domain.SkuStock;
import com.spzx.product.mapper.ProductDetailsMapper;
import com.spzx.product.mapper.ProductMapper;
import com.spzx.product.mapper.ProductSkuMapper;
import com.spzx.product.mapper.SkuStockMapper;
import com.spzx.product.service.IProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品 服务实现类
 * </p>
 *
 * @author gax
 * @since 2025-08-23
 */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductDetailsMapper productDetailsMapper;

    @Autowired
    private ProductSkuMapper productSkuMapper;

    @Autowired
    private SkuStockMapper skuStockMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    // DI 注入线程池对象
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public List<Product> selectProductList() {
        return productMapper.selectProductList();
    }

    // 保存商品，涉及到的信息包括：SPU，SKU 列表，SPU 详情，库存
    // 这个需求应该首先想到事务，对这几张表的操作，要么一次性全部成功；否则失败回滚
    // 事务的特性：原子性，一致性，隔离性，持久性
    @Override
    // @Transactional 默认只在方法抛出 RuntimeException（运行时异常）以及 Error 时才会回滚事务。
    // 对于非运行时异常，如 IOException、SQLException 等）及其子类，默认是不会触发事务回滚的。
    // 故此处指定 rollbackFor = Exception.class
    // 表示如果被注解的方法执行过程中抛出了 Exception 类型的异常（或其子类），则自动回滚整个事务。
    @Transactional(rollbackFor = Exception.class)
    public void saveProduct(Product product) {
        // ① 在数据库的 product 表中，新增一条商品信息，但是有些字段(初始状态，创建人)前端没有携带，需要手动设置
        // 设置商品的初始状态为 0，未上架
        product.setStatus(0);
        // 设置商品的创建人
        product.setCreateBy(SecurityUtils.getUsername());
        // 调用 MP 业务层的 save 方法即可，保存商品 SPU 信息
        this.save(product);
        // 在 BaseEntity 中，id 是 @TableId(type = IdType.AUTO) 注解的，表示主键自动递增
        // MybatisPlus 对于自增主键的回显，底层设置了 userGeneratedKeys 为 true
        // 因此在经过上述 save 方法后，product 对象中的 id 已经自动被赋值
        Long productId = product.getId();
        

        // ② 在数据库的 product_details 表中，新增一条商品详情信息
        ProductDetails productDetails = new ProductDetails();
        productDetails.setProductId(productId);
        productDetails.setCreateBy(SecurityUtils.getUsername());
        // 从 product 对象中取出详情图片列表
        List<String> detailsImageUrlList = product.getDetailsImageUrlList();

        // 使用 Spring 提供的工具类 CollectionUtils，专门用来判断集合是否为空
        if (!CollectionUtils.isEmpty(detailsImageUrlList)) {
            // 将详情图片列表拼接成字符串，用逗号分隔
            String imageUrls = String.join(",", detailsImageUrlList);
            // 将拼接好的字符串设置到 productDetails 对象的 imageUrls 字段中
            productDetails.setImageUrls(imageUrls);
        }
        // 将 productDetails 对象插入到数据库中
        productDetailsMapper.insert(productDetails);


        // ③ 在数据库的 product_sku 表中新增 SKU 信息，同时在数据库的 sku_stock 表中新增 SKU 库存信息
        // 需要从 SPU 商品对象中，取出商品 SKU 列表
        List<ProductSku> productSkuList = product.getProductSkuList();
        if (!CollectionUtils.isEmpty(productSkuList)) {
            // 由于在 Lambda 表达式中，不可以修改外部变量，因为线程安全问题，故使用 AtomicInteger 来保证线程安全
            AtomicInteger index = new AtomicInteger(1);
            productSkuList.forEach(elm -> {
                // SKU 编号：设置为商品 ID_自增 ID
                elm.setSkuCode(productId + "_" + index.getAndIncrement());
                // SKU 名称：设置为商品名称 + SKU 规格
                elm.setSkuName(product.getName() + " " + elm.getSkuSpec());
                // SKU 关联的商品 ID：设置为商品 ID
                elm.setProductId(productId);
                // 设置初始状态
                elm.setStatus((byte)0);
                // 设置创建人
                elm.setCreateBy(SecurityUtils.getUsername());
                // 将 SKU 对象插入到数据库中
                productSkuMapper.insert(elm);
                // 经过 MP 业务层插入后，Mp 会自动给对象的 id 字段赋值
                // 直接获取对象的 id 字段
                Long skuId = elm.getId();
                // 在数据库的 sku_stock 表中新增 SKU 库存信息
                SkuStock skuStock = new SkuStock();
                // 设置库存表关联的 SKU ID
                skuStock.setSkuId(skuId);
                // 设置总库存数
                skuStock.setTotalNum(elm.getStockNum());
                // 设置锁定库存数
                skuStock.setLockNum(0);
                // 设置可用库存数
                skuStock.setAvailableNum(elm.getStockNum());
                // 设置销量
                skuStock.setSaleNum(0);
                // 设置创建人
                skuStock.setCreateBy(SecurityUtils.getUsername());
                // 设置上架状态，默认是 0
                skuStock.setStatus((byte) 0);
                // 将 SKU 库存信息插入到数据库中
                skuStockMapper.insert(skuStock);
            });
        }
    }

    @Override
    // 涉及到一连串的多表更新操作，故添加事务，要么这些表的操作全部一次性成功，要么全部失败谁也别改
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long spuId, Integer status) {
        // ① 修改 product 表的 spu 状态
        this.update(new LambdaUpdateWrapper<Product>()
                .eq(Product::getId,spuId)
                .set(Product::getStatus,status));

        // ② 修改 product_sku 表的 status
        // 下述写法是错误的，因为：
        // ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
        // 因此 this.update(...) 这些来自 ServiceImpl/IService 的方法，期望的 Wrapper 类型是 Wrapper<Product>
        // 所以当前 Service 只服务 Product，不能直接拿 this 的 update 去更新 ProductSku。
//        this.update(new LambdaUpdateWrapper<ProductSku>()
//                .eq(ProductSku::getProductId, spuId).set(ProductSku::getStatus, status))

        // 解决方案是用 ProductSku 对应的 Mapper 对象调 update
        productSkuMapper.update(null, new LambdaUpdateWrapper<ProductSku>()
                .eq(ProductSku::getProductId,spuId)
                .set(ProductSku::getStatus,status));

        // ③ 修改 sku_stock 表的 status
        // 需要先从 product_sku 表查询出商品的 sku id 列表
        LambdaQueryWrapper<ProductSku> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProductSku::getProductId, spuId);
        List<ProductSku> productSkuList = productSkuMapper.selectList(queryWrapper);
        List<Long> skuIdList = productSkuList.stream().map(elm -> elm.getId()).toList();
        // 根据 sku id 列表去更新 sku_stock
        skuStockMapper.update(null, new LambdaUpdateWrapper<SkuStock>()
                .set(SkuStock::getStatus, status)
                .in(SkuStock::getSkuId,skuIdList));

        // 处理 bitmap 位图，如果是上架：将商品 skuid 加入到 bitmap 中；如果是下架：从 bitmap 中删除 skuid
        skuIdList.forEach(skuId -> {
            if (status == 1) {
                redisTemplate.opsForValue().setBit("product:sku:data", skuId, true);
            } else if (status == -1) {
                redisTemplate.opsForValue().setBit("product:sku:data", skuId, false);
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deletePorductByIds(List<Long> spuIds) {
        // 删除 spu 表
        this.removeBatchByIds(spuIds);
        // 根据商品 spuid 查询 skuid 列表
        LambdaQueryWrapper<ProductSku> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ProductSku::getProductId,spuIds);
        List<ProductSku> productSkuList = productSkuMapper.selectList(queryWrapper);

        if (!CollectionUtils.isEmpty(productSkuList)) {
            List<Long> skuIdList = productSkuList.stream().map(elm -> elm.getId()).toList();
            // 删除商品 sku 表
            productSkuMapper.deleteBatchIds(skuIdList);
            // 删除商品 sku 库存表
            skuStockMapper.delete(new LambdaQueryWrapper<SkuStock>().in(SkuStock::getSkuId,skuIdList));
        }
        // 删除商品 spu 详情表
        productDetailsMapper.delete(new LambdaQueryWrapper<ProductDetails>().in(ProductDetails::getProductId,spuIds));
        return 1;
    }
}
